最近在开发的时候,使用 @Autowired 注解 Field,发现 IDE 报了一个警告,如下:
1 | Spring Team recommends "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies". |
翻译后的大概意思就是:
Spring 团队建议:总是在您的 bean 中使用构造函数建立依赖注入。总是使用断言强制依赖。
原来的写法是:
1 | @Controller |
public class A {
/**
* 注意多添加了一个 final 修饰
*/
private final B b;
@Autowired
public A(B b) {
this.b = b;
}
...
}1
2
3
4
5
6
7
8
9
10@Autowired 明明可以对 Constructor,Fileld, Setter Methods or config Methods 进行注释。
那么为什么这里有这样的提示?对 Field 和 对 Constructor 进行注释有什么区别呢?
为了解答以上疑惑,还得结合 JVM 中对 Java 变量的初始化顺序进行分析:
**Java变量的初始化顺序为:**
静态变量或静态语句块 –> 实例变量或初始化语句块 –> 构造方法 –> @Autowired
所以,若有如下代码:
B.java 文件
@Getter
@Setter
@Service
public class B {
private String name;
private int age;
public User(){}
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Name=" + name + ", Age=" + age;
}
}1
2
A.java 文件
public class A {
private String name;
@Autowired
private B b;
public A() {
this.name = b.getName();
}
...
}
```
能正常完成编译,但是运行时会抛出 NPE。
被 @Autowired 注解的 Field 的底层注入流程可以理解为在配置文件中配置 bean,然后使用 setter 注入。
而被 @Autowired 注解的 Constructor 的底层注入流程就相当于是使用构造函数进行依赖注入了。